package com.aiju.support.aop;

import android.util.Log;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: 佐为
 * @date: 2017-03-21 16:21
 * @version: V1.0
 * @Description: 拦截执行者
 */
public abstract class AInterceptorHandler implements IInterceptorHandler {

    public static final Object DEFAULT = Integer.valueOf(0);
    public static final Object END = Integer.valueOf(1);
    protected List<IInterceptor> interceptors;
    protected Object proxied;
    protected List<String> methodNames = new ArrayList();

    public AInterceptorHandler() {
    }

    @Override
    public Object bind(Object proxied, List<IInterceptor> interceptors) {
        this.proxied = proxied;
        this.interceptors = interceptors;
        Class clazz = this.proxied.getClass();
        Object proxy = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
        Log.d("AInterceptorHandler", "proxy=" + proxy);
        return proxy;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        boolean canIntercept = this.canIntercept(methodName);
        if (canIntercept) {
            Object result = null;
            Object beforeResult = this.before(this.proxied, method, args);
            if (beforeResult.equals(END)) {
                return result;
            } else {
                result = method.invoke(this.proxied, args);
                Object afterResult = this.after(this.proxied, method, args, result);
                Log.d("AInterceptorHandler", "afterResult=" + afterResult);
                return result;
            }
        } else {
            return method.invoke(this.proxied, args);
        }
    }

    @Override
    public void registerMethod(String methodName) {
        if (methodName != null) {
            this.methodNames.add(methodName);
        }

    }

    @Override
    public void unregisterMethod(String methodName) {
        if (methodName != null) {
            this.methodNames.remove(methodName);
        }

    }

    @Override
    public boolean canIntercept(String methodName) {
        return this.methodNames.contains(methodName);
    }

    protected Object before(Object proxy, Method method, Object[] args) {
        Object result = DEFAULT;
        int size = this.interceptors.size();

        for (int i = 0; i < size; ++i) {
            result = this.interceptors.get(i).before(proxy, method, args);
            if (result.equals(END)) {
                return result;
            }
        }

        return result;
    }

    protected Object after(Object proxy, Method method, Object[] args, Object methodReturn) {
        Object result = DEFAULT;
        int size = this.interceptors.size();

        for (int i = size - 1; i >= 0; -- i) {
            result = this.interceptors.get(i).after(proxy, method, args, methodReturn);
        }

        return result;
    }
}